/*
 * Copyright 2011-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.sabayframework.mem.impl.disk;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

public final class DataEntry implements Comparable<DataEntry> {
	
	public static final int MAX_FILES_EXP = 16;
	public static final long MAX_NUMBER_OF_LOG_FILES = (1 << MAX_FILES_EXP)-1;
	public static final int MAX_SIZE_EXP = 64-MAX_FILES_EXP;
	public static final long MAX_SIZE_OF_LOG_FILE = (1L << MAX_SIZE_EXP)-1;
	private static final long MAX_FILES_MASK = (MAX_NUMBER_OF_LOG_FILES << MAX_SIZE_EXP);
	
	private long address;
	private int length;
	// higher bits: log file number, lower bits - offset
	private long logPosition;
	
	public DataEntry() {
	}
		
	public DataEntry(long addr, int length, int logFile, long logOffset) {
		super();
		this.address = addr;
		setLength(length);
		setLogFile(logFile);
		setLogOffset(logOffset);
	}

	public long getAddress() {
		return address;
	}
	public void setAddress(long address) {
		this.address = address;
	}
	public int getLength() {
		return length;
	}
	public void setLength(int length) {
		if(length < 0) throw new IllegalArgumentException("length = "+length);
		this.length = length;
	}
	public int getLogFile() {
		return (int)(logPosition >>> MAX_SIZE_EXP);
	}
	public void setLogFile(int logFile) {
		if(logFile < 0 || logFile > MAX_NUMBER_OF_LOG_FILES) throw new IllegalArgumentException("log file = "+logFile);
		logPosition = (((long)logFile) << MAX_SIZE_EXP) + (logPosition & MAX_SIZE_OF_LOG_FILE);
	}
	public long getLogOffset() {
		return logPosition & MAX_SIZE_OF_LOG_FILE;
	}
	public void setLogOffset(long logOffset) {
		if(logOffset < 0 || logOffset > MAX_SIZE_OF_LOG_FILE) throw new IllegalArgumentException("log offset = "+logOffset);
		logPosition = (logPosition & MAX_FILES_MASK) + logOffset;
	}
	public static int sizeOf(){
		return 20; 
	}
	public int compareTo(DataEntry e) {
		long diff = address - e.address;
		return diff < 0 ? -1 : diff == 0? 0: 1;
	}

	@Override
	public int hashCode() {
		return (int) (address ^ (address >> 32));
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		DataEntry other = (DataEntry) obj;
		if (address != other.address)
			return false;
		return true;
	}
	protected void writeTo(DataOutputStream dos) throws IOException{
		dos.writeLong(address);
		dos.writeInt(length);
		dos.writeLong(logPosition);
	}
	protected void readFromTo(DataInputStream is) throws IOException{
        address = is.readLong();
        length = is.readInt();
        logPosition  = is.readLong();
	}
	
}
